#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 09-Nov-09 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.Drawing;

using Thn;
using Thn.Drawing.Painters;
#endregion

namespace Thn.Interface.Vcl.Themes.BlueSea
{
    /// <summary>
    /// Custom renderer for <see cref="Listbox"/>.
    /// </summary>
#if DEBUG
    public
#else
    public
#endif
 class ListboxRenderer : BlueThemeRendererBase
    {
        #region On Render Content
        /// <summary>
        /// Paint the control's content (text, value, data, etc.) onto canvas.
        /// </summary>
        /// <param name="control">The control to be rendered.</param>
        /// <param name="canvas">The canvas on which to paint the control.</param>
        /// <param name="context">The current drawing context.</param>
        protected override void OnRenderContent(IControl control, Graphics canvas, RenderContext context)
        {
            ListBoxRenderContext rc = (ListBoxRenderContext)context;
            ListBox con = (ListBox)control;
            ITheme theme = con.EffectiveTheme;

            #region Find font
            IFontStyle font = null;
            if (con.TextStyle == TextStyle.Normal)
            {
                font = theme.FindFont(StyleNames.List);
            }
            else if (con.TextStyle == TextStyle.Custom)
            {
                #region Use font specified in the control
                font = new SimpleFontStyle(con.Font, con.ForeColor);
                #endregion
            }
            else
            {
                string stylename = string.Format("{0}", con.TextStyle);
                font = theme.FindFont(stylename);
            }
            #endregion

            #region Render text
            //render the text
            if (font != null)
            {
                // set clip
                Region originClip = canvas.Clip;
                canvas.Clip = new Region(rc.CellsRegion);

                #region Draw items's visual
                int rowIdx = rc.StartRowIndex;
                int top = rowIdx * rc.RowHeight - rc.OffsetY + rc.CellsRegion.Top;
                for (int i = 0; i < rc.RenderedRowCount; i++)
                {
                    // render item background
                    ListboxVisibleItemInfo info = rc.VisibleItems[rowIdx];
                    Rectangle rRow = new Rectangle(rc.CellsRegion.Left, top, rc.CellsRegion.Width, rc.RowHeight);
                    OnRenderItemContent(con, canvas, rc, info, rRow, font);

                    rowIdx++;
                    top += rc.RowHeight;
                }
                #endregion

                canvas.Clip = originClip;
            }
            #endregion

            #region Find title's font
            font = null;
            if (con.TextStyle == TextStyle.Normal)
            {
                if (con.Focused) font = theme.FindFont(StyleNames.ListHeadingFocused);
                else font = theme.FindFont(StyleNames.ListHeading);
            }
            else if (con.TextStyle == TextStyle.Custom)
            {
                #region Use font specified in the control
                font = new SimpleFontStyle(con.Font, con.ForeColor);
                #endregion
            }
            else
            {
                string stylename = string.Format("{0}", con.TextStyle);
                font = theme.FindFont(stylename);
            }
            #endregion

            #region Render text
            //render the text
            if (font != null)
            {
                // set clip
                Region originClip = canvas.Clip;
                canvas.Clip = new Region(rc.TitleRegion);

                #region Draw items's visual
                OnRenderTitleContent(con, canvas, rc, rc.TitleRegion, font);
                #endregion

                canvas.Clip = originClip;
            }
            #endregion

            #region Defensive tracing
            else
            {
                //font is not assigned, forget about drawing
            }
            #endregion

        }
        #endregion

        #region On Render Visual
        /// <summary>
        /// Paint the control's visual stuff (border, background, etc.) onto canvas.
        /// </summary>
        /// <param name="control">The control to be rendered.</param>
        /// <param name="canvas">The canvas on which to paint the control.</param>
        /// <param name="context">The current drawing context.</param>
        protected override void OnRenderVisual(IControl control, Graphics canvas, RenderContext context)
        {
            ListBoxRenderContext rc = (ListBoxRenderContext)context;
            ListBox con = (ListBox)control;

            #region Fill background
            Brush b = new SolidBrush(con.BackColor);
            canvas.FillRectangle(b, con.ClientRectangle);
            b.Dispose();
            #endregion

            #region modify regions for border
            if (rc.OriginTitleRegion.Height > 0)
            {
                Rectangle tmp = rc.OriginTitleRegion;
                //modify the title region
                rc.TitleRegion = new Rectangle(tmp.Left + 1, tmp.Top + 1, tmp.Width - 2, tmp.Height - 1);

                tmp = rc.OriginCellsRegion;
                rc.CellsRegion = new Rectangle(tmp.Left + 1, tmp.Top, tmp.Width - 2, tmp.Height - 1);
            }
            else
            {
                rc.TitleRegion = rc.OriginTitleRegion;
                Rectangle tmp = rc.OriginCellsRegion;
                rc.CellsRegion = new Rectangle(tmp.Left + 1, tmp.Top + 1, tmp.Width - 2, tmp.Height - 2);
            }
            #endregion

            #region find image
            ITheme theme = con.EffectiveTheme;
            rc.CheckImage = theme.FindImage(ImageNames.Check);
            #endregion

            #region Draw items's visual
            int rowIdx = rc.StartRowIndex;
            int top = rowIdx * rc.RowHeight - rc.OffsetY + rc.CellsRegion.Top;
            for (int i = 0; i < rc.RenderedRowCount; i++)
            {
                // render item background
                ListboxVisibleItemInfo info = rc.VisibleItems[rowIdx];
                info.ContentLeft = 0;
                Rectangle rRow = new Rectangle(rc.CellsRegion.Left, top, rc.CellsRegion.Width, rc.RowHeight);
                OnRenderItemVisual(con, canvas, rc, info, rRow, rowIdx);

                rowIdx++;
                top += rc.RowHeight;
            }
            #endregion

            #region Draw title region
            OnRenderTitleVisual(con, canvas, rc);
            #endregion

            #region Draw border
            // control border
            //Rectangle rControl = new Rectangle(0, 0, con.Width, con.Height);
            Rectangle rControl = new Rectangle(0, 0,
                rc.OriginCellsRegion.Width - 1,
                rc.OriginTitleRegion.Height + rc.OriginCellsRegion.Height);
            rControl.Inflate(0, -1);
            PainterBase borderPaint = null;
            borderPaint = new White3D();
            borderPaint.PaintRectangle(canvas, rControl, true, false);

            #endregion
        }
        #endregion

        #region Draw Item Visual
        #region On Render Item Visual
        /// <summary>
        /// Render a item's visual.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rRow">Rectangle of row.</param>
        /// <param name="rowIndex">Row index.</param>
        /// <param name="info">Visible information.</param>
        protected virtual void OnRenderItemVisual(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle rRow, int rowIndex)
        {
            bool isEnabled = con.Enabled;

            #region Draw background
            #region Draw background
            //draw one cell
            if (rowIndex == rc.SelectedItemIndex)
            {
                OnRenderSelectedItemBackground(con, canvas, rc, info, rRow, rowIndex);
            }
            else
            {
                OnRenderItemBackground(con, canvas, rc, info, rRow, rowIndex);
            }
            #endregion
            #endregion

            #region Draw hover
            //draw hover
            if (rowIndex == rc.HoverIndex)
            {
                OnRenderHoverCue(con, canvas, rc, rRow);
            }
            #endregion

            #region Draw tree
            // draw tree
            if (rc.HasSubItems)
            {
                OnRenderTreeForItem(con, canvas, rc, info, rRow, rowIndex);
            }
            #endregion

            // fix icon size
            int iconSize = rc.RowHeight - rc.RowPaddding / 2;

            #region Optional ( draw check )
            if ((con.DrawCheck) && (rc.CheckImage != null))
            {
                OnRenderCheck(con, canvas, rc, info, rc.CheckImage, new Rectangle(info.ContentLeft, rRow.Top + rc.RowPaddding / 2, iconSize, iconSize));
            }
            #endregion

            #region Draw image
            OnRenderIcon(con, canvas, rc, info, new Rectangle(info.ContentLeft, rRow.Top + rc.RowPaddding / 2, iconSize, iconSize));
            #endregion
        }
        #endregion

        #region Draw Item Background
        /// <summary>
        /// Draw item's background.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rRow">Rectangle of row.</param>
        /// <param name="rowIndex">Row index.</param>
        /// <param name="info">Visible information.</param>
        protected virtual void OnRenderItemBackground(
            ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info,
            Rectangle rRow, int rowIndex
            )
        {
            PainterBase painter = null;
            if (con.Enabled)
            {
                painter = new WhiteFlat();

                if (rowIndex % 2 == 0)
                {
                    painter.FillColor = con.EvenItemBackgroundColor;
                }
                else
                {
                    painter.FillColor = con.OddItemBackgoundColor;
                }
            }
            else
            {
                if (rowIndex % 2 == 0) painter = new WhiteFlat();
                #region Defensive tracing
                else
                {
                    // do not need to sepererate item backgound color in this case.
                }
                #endregion
            }

            if (painter != null) painter.PaintRectangle(canvas, rRow, false, true);
            #region Defensive tracing
            else
            {
                //painter is null
            }
            #endregion
        }

        /// <summary>
        /// Draw selected item background.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rRow">Rectangle of row.</param>
        /// <param name="rowIndex">Row index.</param>
        /// <param name="info">Visible information.</param>
        protected virtual void OnRenderSelectedItemBackground(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle rRow, int rowIndex)
        {
            PainterBase painter = null;
            if (con.Enabled)
            {
                //painter = new LightBlue3D();
                //painter = new OrangeGloss();

                if (con.Focused) painter = new LightYellowFlat();
                else painter = new WhiteGloss();
            }
            else
            {
                painter = new DarkGray3D();
            }
            Rectangle rectRow = new Rectangle(rRow.Left, rRow.Top, rRow.Width - 1, rRow.Height - 1);
            painter.PaintRectangle(canvas, rectRow, true, true);
        }
        #endregion

        #region Draw Tree For Item
        /// <summary>
        /// Draw the tree structure for item.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rRow">Rectangle of row.</param>
        /// <param name="rowIndex">Row index.</param>
        /// <param name="info">Visible information.</param>
        protected virtual void OnRenderTreeForItem(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle rRow, int rowIndex)
        {
            int level = info.Level;
            int midRow = rRow.Top + rRow.Height / 2;
            int left = rRow.Left + rc.RowPaddding;
            int signPad = rc.SignPad;
            int dx = left + signPad / 2;
            bool moreSiblings = !info.LastSibling;
            bool firstSiblings = info.FirstSibling;


            rc.LevelCue[level] = moreSiblings;

            #region get the paint for draw line
            Pen p = null;
            Pen signPen = null;
            Brush signBrush = null;

            if (con.Enabled)
            {
                p = new Pen(Color.DodgerBlue);
                signPen = new Pen(Color.DodgerBlue);
                signBrush = new SolidBrush(Color.White);
            }
            else
            {
                p = new Pen(Color.Gray);
                signPen = new Pen(Color.Gray);
                signBrush = new SolidBrush(Color.LightGray);
            }
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            #endregion

            #region draw vertical lines
            for (int i = 1; i <= level; i++)
            {
                int ly1 = rRow.Top;
                if ((level == 1) && (firstSiblings)) ly1 = midRow;//very first item of listbox
                int ly2 = rRow.Bottom;
                int lx = left + i * signPad - signPad / 2;

                if (i < level)
                {//previous level
                    if ((bool)rc.LevelCue[i]) canvas.DrawLine(p, lx, ly1, lx, ly2);
                }
                else
                {//current level
                    if ((level > 1) && (firstSiblings)) ly1 -= signPad / 3;
                    if (!moreSiblings) ly2 = midRow;
                    canvas.DrawLine(p, lx, ly1, lx, ly2);
                }
            }
            #endregion

            #region Draw horizontal lines
            //draw horizontal line
            int lx2 = left + level * signPad;
            int lx1 = lx2 - signPad / 2;
            canvas.DrawLine(p, lx1, midRow, lx2, midRow);

            #endregion

            #region draw sign if has children
            if ((info.Item.Children != null) && (info.Item.Children.Count > 0))
            {
                int ds = (int)(rc.RowHeight * 0.25);
                OnRenderTreeNodeSign(con, canvas, rc, info,
                    new Rectangle(lx1 - ds, midRow - ds, ds * 2, ds * 2),
                    signPen, signBrush);
            }
            #endregion

            //add padding for further drawing
            left += signPad * level;

            // re assign the content position
            info.ContentLeft = left;
        }
        #endregion

        #region Draw Sign
        /// <summary>
        /// Draw tree node sign
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rSign">Rectangle of sign.</param>
        /// <param name="info">Visible information.</param>
        /// <param name="brush">Brush for filling.</param>
        /// <param name="pen">Pen for stroking.</param>
        protected virtual void OnRenderTreeNodeSign(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle rSign, Pen pen, Brush brush)
        {
            //IStyle style = ThemeManager.CurrentTheme.Styles[StyleNames.ControlNormal];
            rSign.Inflate(-2, -2);
            float pad = rSign.Width * 0.25f;

            //fill rectable
            if (brush != null)
            {
                canvas.FillRectangle(brush, rSign);
            }
            //draw rectangle
            canvas.DrawRectangle(pen, rSign);

            //draw sign
            float midy = rSign.Top + rSign.Height / 2;
            if (!info.Item.IsExpanded)
            {
                float midx = rSign.Left + rSign.Width / 2;
                canvas.DrawLine(pen, midx, rSign.Top + pad, midx, rSign.Bottom - pad);
            }
            canvas.DrawLine(pen, rSign.Left + pad, midy, rSign.Right - pad, midy);

        }
        #endregion

        #region Draw Hover Cue
        /// <summary>
        /// Draw hover cue.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="rRow">Hover row region.</param>
        protected virtual void OnRenderHoverCue(ListBox con, Graphics canvas, ListBoxRenderContext rc, Rectangle rRow)
        {
            // get painter
            //PainterBase hoverPaint = new OrangeGloss();
            PainterBase hoverPaint = null;
            if (rc.HoverIndex == rc.SelectedItemIndex)
            {
                //hoverPaint = new BlueGloss();
                hoverPaint = new LightYellowFlat();
            }
            else
            {
                //hoverPaint = new OrangeGloss();
                hoverPaint = new LightBlueGloss();
            }
            //hoverRow.Inflate(-1, -1);

            Rectangle rectRow = new Rectangle(rRow.Left, rRow.Top, rRow.Width - 1, rRow.Height - 1);
            hoverPaint.PaintRectangle(canvas, rectRow, true, true);
        }
        #endregion

        #region Draw check
        /// <summary>
        /// Draw check icon before item.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="info">Visible information.</param>
        /// <param name="icon">Check icon, has been get from theme from caller.</param>
        /// <param name="iconPosition">Position to draw icon.</param>
        protected virtual void OnRenderCheck(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Image icon, Rectangle iconPosition)
        {
            info.ContentLeft += iconPosition.Width + rc.RowPaddding;
            if (info.Item.Checked)
            {
                iconPosition.Inflate(-3, -3);
                //draw
                canvas.TranslateTransform(-0.5f, -0.5f);//fix pixel offset bug
                canvas.DrawImage(icon, iconPosition);
                canvas.TranslateTransform(0.5f, 0.5f);//fix pixel offset bug
            }
        }
        #endregion

        #region Draw Icon
        /// <summary>
        /// Draw check icon before item.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="info">Visible information.</param>
        /// <param name="icon">Check icon, has been get from theme from caller.</param>
        /// <param name="iconPosition">Position to draw icon.</param>
        protected virtual void OnRenderIcon(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle iconPosition)
        {
            if (info.Item.Image != null)
            {
                info.ContentLeft += iconPosition.Width + rc.RowPaddding;

                iconPosition.Inflate(-3, -3);

                //draw
                canvas.TranslateTransform(-0.5f, -0.5f);//fix pixel offset bug
                canvas.DrawImage(info.Item.Image, iconPosition);
                canvas.TranslateTransform(0.5f, 0.5f);//fix pixel offset bug


            }
        }
        #endregion
        #endregion

        #region Draw Title Visual
        /// <summary>
        /// Draw title visual.
        /// </summary>
        /// <param name="canvas">Canvas</param>
        /// <param name="titleRegion">Title region</param>
        /// <param name="rc">Render context.</param>
        /// <param name="columns">Column infors</param>
        protected virtual void OnRenderTitleVisual(ListBox con, Graphics canvas, ListBoxRenderContext rc)
        {
            ListBoxColumnList columns = con.Columns;
            Rectangle titleRegion = rc.TitleRegion;

            if (titleRegion.Height > 0)
            {
                bool drawMultiColumn = ((columns != null) && (columns.Count > 1));

                //Region originClip = canvas.Clip;
                // set clip for drawing
                //canvas.Clip = new Region(titleRegion);
                #region Get painter
                // column painter
                PainterBase painter = null;
                if (con.Enabled)
                {
                    //painter = new LightBlueGloss();

                    if (con.Focused) painter = new DeepBlueGloss();
                    else painter = new WhiteGloss();
                }
                else
                {
                    painter = new GrayGloss();
                }
                #endregion

                #region Draw


                // fill first
                painter.PaintRectangle(canvas, titleRegion, false, true);

                Pen pen = new Pen(painter.BorderColor);

                canvas.TranslateTransform(-0.5f, -0.5f); // fix pixel offset.
                // then draw column seperators
                if (drawMultiColumn)
                {
                    int left = titleRegion.Left - 1;

                    for (int i = 0; i < columns.Count - 1; i++)
                    {
                        left += columns[i].Width;
                        canvas.DrawLine(pen, left, titleRegion.Top, left, titleRegion.Bottom);
                    }
                }
                #region Defensive
                else
                {

                }
                #endregion

                // draw bottom line
                canvas.DrawLine(pen, titleRegion.Left, titleRegion.Bottom, titleRegion.Right, titleRegion.Bottom);

                canvas.TranslateTransform(0.5f, 0.5f); // fix pixel offset.
                #endregion
            }
        }
        #endregion

        #region Draw Item Content
        /// <summary>
        /// Render item's content.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="info">Visible information.</param>
        /// <param name="font">Font for drawing text.</param>
        /// <param name="rRow">Row region.</param>
        /// <param name="rowIndex">Index of the row to be rendered.</param>
        protected virtual void OnRenderItemContent(ListBox con, Graphics canvas, ListBoxRenderContext rc, ListboxVisibleItemInfo info, Rectangle rRow, IFontStyle font)
        {
            ListBoxColumnList columns = con.Columns;
            if ((columns != null) && (columns.Count > 0))
            {
                // draw multi column
                int left = rRow.Left;
                int top = rRow.Top;
                Rectangle cell;
                info.ContentLeft += rc.RowPaddding;
                for (int i = 0; i < columns.Count; i++)
                {
                    ListBoxColumn column = columns[i];

                    if (i == 0)
                    {
                        cell = new Rectangle(info.ContentLeft, top, column.Width - info.ContentLeft, rRow.Height);
                    }
                    else
                    {
                        cell = new Rectangle(left, top, column.Width, rRow.Height);
                    }

                    OnRenderColumnContent(con, canvas, cell, font, info.Item[i], i, column.Alignment, info.Item);

                    left += column.Width;
                }
            }
            else
            {
                info.ContentLeft += rc.RowPaddding;
                Rectangle cell = new Rectangle(info.ContentLeft, rRow.Top, rRow.Width - info.ContentLeft, rRow.Height);
                OnRenderColumnContent(con, canvas, cell, font, info.Item.Text, 0, ContentAlignment.MiddleLeft, info.Item);
            }
        }

        /// <summary>
        /// Render item's data at sepecified column.
        /// </summary>
        protected virtual void OnRenderColumnContent(ListBox con, Graphics canvas, Rectangle rCell, IFontStyle font, string content, int columnIdx, ContentAlignment alignment, ListBoxItem item)
        {
            font.DrawString(content, canvas, rCell, alignment, false);
        }
        #endregion

        #region Draw Column Content
        /// <summary>
        /// Render item's content.
        /// </summary>
        /// <param name="con">Listbox control.</param>
        /// <param name="rc">Listbox render contest.</param>
        /// <param name="canvas">Drawing canvas.</param>
        /// <param name="font">Title font.</param>
        /// <param name="rTitle">Title region.</param>
        protected virtual void OnRenderTitleContent(ListBox con, Graphics canvas, ListBoxRenderContext rc, Rectangle rTitle, IFontStyle font)
        {
            ListBoxColumnList columns = con.Columns;
            if ((columns != null) && (columns.Count > 0))
            {
                // draw multi column
                int left = rTitle.Left;
                int top = rTitle.Top;
                Rectangle cell;
                for (int i = 0; i < columns.Count; i++)
                {
                    ListBoxColumn column = columns[i];
                    cell = new Rectangle(left, top, column.Width, rTitle.Height);

                    OnRenderTitleColumnContent(canvas, cell, font, column.Text, ContentAlignment.MiddleCenter);

                    left += column.Width;
                }
            }
            #region Defensive
            else
            {
                // there are no text to draw
            }
            #endregion
        }

        /// <summary>
        /// Render item's data at sepecified column.
        /// </summary>
        protected virtual void OnRenderTitleColumnContent(Graphics canvas, Rectangle rCell, IFontStyle font, string content, ContentAlignment alignment)
        {
            font.DrawString(content, canvas, rCell, alignment, false);
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public ListboxRenderer()
        {
            mDrawVisualCues = false;
        }
        #endregion
    }
}
